﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading;

namespace Superstore.Vender.PushMessage
{
    public enum UserIdType
    {
        NormalId,
        WeixinId
    }
    public class MessageMgr
    {
        private class MessagePool
        {
            private Dictionary<string, UserMessage> mUsersList;
            private DateTime mLastRecycle;
            public MessagePool()
            {
                mUsersList = new Dictionary<string,UserMessage>();
                mLastRecycle = DateTime.Now;
            }

            public UserMessage GetUserMessage(string userId, string tick)
            {
                lock(mUsersList)
                {
                    UserMessage userMsg;
                    bool result = mUsersList.TryGetValue(userId, out userMsg);
                    if (true == result)
                    {
                        if (tick.Equals(userMsg.LastTick))
                        {
                            mUsersList.Remove(userId);
                            return UserMessage.EMPTY;
                        }
                        else
                        {
                            return userMsg;
                        }
                    }
                    else
                    {
                        return UserMessage.EMPTY;
                    }
                }
            }

            public void AdduserMessage(string userId, Message msg)
            {
                lock(mUsersList)
                {
                    UserMessage userMsg;
                    bool result = mUsersList.TryGetValue(userId, out userMsg);
                    if (true == result)
                    {
                        userMsg.AddMessage(msg);
                    }
                    else
                    {
                        userMsg = new UserMessage(userId);
                        userMsg.AddMessage(msg);
                        mUsersList.Add(userId, userMsg);
                    }
                }
            }

            private static readonly TimeSpan RECYCLEINTERVAL = new TimeSpan(0, 30, 0);

            public void Recycle()
            {
                lock(mUsersList)
                {
                    Dictionary<string, UserMessage> tmp = new Dictionary<string, UserMessage>();
                    foreach(var item in mUsersList)
                    {
                        if ((DateTime.Now - item.Value.LastUpdate) < RECYCLEINTERVAL)
                        {
                            tmp.Add(item.Key, item.Value);
                        }
                    }
                    mUsersList = tmp;
                }
            }            
        }

        private int mNormalPoolNum = 0;
        private int mWeixinPoolNum = 0;
        private List<MessagePool> mPoolList;
        private Timer mTimer;

        private static MessageMgr _instance = new MessageMgr();
        public static MessageMgr Getinstance()
        {
            return _instance;
        }

        private MessageMgr()
        {
            InitPools(5, 5);
            mTimer = new Timer(this.OnTimer, null, 5 * 60 * 1000, 60 * 1000);
        }

        private void InitPools(int iNormalNum, int iWeixinNum)
        {
            mPoolList = new List<MessagePool>(iNormalNum + iWeixinNum);
            for (int i = 0; i < (iNormalNum + iWeixinNum); i++)
            {
                mPoolList.Add(new MessagePool());
            }
            mNormalPoolNum = iNormalNum;
            mWeixinPoolNum = iWeixinNum;
        }

        void OnTimer(object obj)
        {
            foreach (var item in mPoolList)
            {
                item.Recycle();
            }
        }

        public UserMessage GetUserMessage(UserIdType type, string userId, string tick)
        {
            MessagePool pool = GetPool(type, userId);
            if (null != pool)
            {
                return pool.GetUserMessage(userId, tick);
            }
            else
            {
                return UserMessage.EMPTY;
            }
        }

        public void AddUserMessage(UserIdType type, string userId, Message msg)
        {
            MessagePool pool = GetPool(type, userId);
            if (null != pool)
            {
                pool.AdduserMessage(userId, msg);
            }
        }

        private MessagePool GetPool(UserIdType type, string userid)
        {
            UInt32 num = ELFHash(userid);
            if (type == UserIdType.NormalId)
            {
                int index = (int)(num%mNormalPoolNum);
                return mPoolList[index];
            }
            else if (type == UserIdType.WeixinId)
            {
                int index = (int)(num%mWeixinPoolNum);
                return mPoolList[mNormalPoolNum + index];
            }
            else
            {
                throw new Exception("unknown userId type:" + type.ToString());
            }
        }

        private UInt32 ELFHash(string str)
        {
            UInt32 hash = 0;
            UInt32 x = 0;
            int i = 0;
            byte[] b = System.Text.Encoding.ASCII.GetBytes(str);
            while (i < str.Length)
            {
                hash = (hash << 4) + (UInt32)b[i];
                if ((x = hash & 0xF0000000) != 0)
                {
                    hash ^= (x >> 24);
                    hash &= ~x;
                }
                i++;
            }
            hash = hash & 0x7FFFFFFF;
            return hash;
        }
    }
}